#include "threadPool.h"
int exitpipe[2];
/* Usage:  */
void handler(int signum){
    printf("signum = %d\n",signum);
    write(exitpipe[1],"1",1);//向子进程发送一个信号,让子进程结束
}
int main(int argc,char*argv[]){
    //创建管道用于主进程和子进程之间的通信(异步调用同步)
    pipe(exitpipe);
    if(fork()){
        //父进程
        close(exitpipe[0]);//先关闭主进程的读端
        signal(SIGUSR1,handler);
        wait(NULL);//等待子进程退出
        printf("父进程已退出\n");
        exit(0);
    }
    //只有子进程能到达此处

    //初始化日志系统
         //myserver 表示日志前缀,会作为标识
         //LOG_PID 表示记录当前进程的PID,LOG_CONS 表示不进日志系统时输出到控制台
         //第三个参数: 日志分类,这里用 LOG_USER 表示用户级程序
    openlog("myserver",LOG_PID | LOG_CONS, LOG_USER);

    close(exitpipe[1]);//先关闭子进程的写端
                       // ./main ip 端口 进程数量
    int workNum = atoi(argv[3]);//记录子进程数量
    threadPool_t threadPool;//创建服务端结构
    threadPoolInit(&threadPool,workNum);//初始化服务端结构
    makeWorker(&threadPool); //初始化服务端结构之后,创建线程
    int sockfd;
    tcpInit(&sockfd,argv[1],argv[2]);
    int epfd = epoll_create(1);
    epollAdd(epfd,sockfd);//监听客户端的连接,如果有连接请求,则添加进任务队列,唤醒所有子线程
    epollAdd(epfd,exitpipe[0]);//监听主进程 ,有数据进来说明要结束了

    struct epoll_event readyset[1024];//已经就绪的文件描述符集合
    while(1){
        int readyNum = epoll_wait(epfd,readyset,1024,-1);
        //用来接收客户端的信息
        struct sockaddr_in client_addr; 
        socklen_t client_addr_len = sizeof(client_addr);
        for(int i = 0;i < readyNum;i++){
            if(readyset[i].data.fd == sockfd){
                //此时说明有客户端发起了连接请求
                int netfd = accept(sockfd,(struct sockaddr*)&client_addr,&client_addr_len);
                ERROR_CHECK(netfd,-1,"accept_netfd_error");
                char* client_ip = inet_ntoa(client_addr.sin_addr);
                log_client_connect(client_ip);// 记录连接日志
                printf("主线程接收到了客户端链接请求 netfd = %d\n",netfd);
                //加锁后将任务添加进任务队列(防止子线程读到未初始化的任务)
                pthread_mutex_lock(&threadPool.mutex);
                taskAdd(&threadPool.taskQueue,netfd,client_ip);
                pthread_cond_broadcast(&threadPool.cond);//唤醒所用子线程
                pthread_mutex_unlock(&threadPool.mutex);
            }else if(readyset[i].data.fd == exitpipe[0]){
                //此刻接收到了主进程发送过来的结束请求
                printf("线程池正在退出...\n");
                pthread_mutex_lock(&threadPool.mutex);
                threadPool.exitflag = 1;//将exitflag置为1,子线程检测到之后 则优雅退出
                pthread_cond_broadcast(&threadPool.cond);//唤醒所有子线程
                pthread_mutex_unlock(&threadPool.mutex);

                for(int j = 0; j < workNum; j++){
                    //循环等待,指导每个子进程都已经退出
                    pthread_join(threadPool.tidArr.arr[j],NULL);
                }
                printf("子线程已经全部退出..主线程退出!\n");
                return 0;
            }
        }
    }


    return 0;
}

